#pragma once
#include <iostream>
#include <pthread.h>
#include <unistd.h>
#include <queue>
#include "Mutex.hpp"//封装的锁
#include "Cond.hpp"//封装的条件变量
//version 2
namespace BlockQueueModule
{
    using namespace CondModule;
    using namespace MutexModule;
    int gbq_num = 5;
    template <class T>
    class BlockQueue
    {
    private:
        bool IsFull()
        {
            return _bq.size() == _bq_num;
        }
        bool IsEmpty()
        {
            return _bq.size() == 0;
        }

    public:
        BlockQueue(int bq_num = gbq_num) : _bq_num(bq_num)
        {
        }
        ~BlockQueue()
        {
        }
        void EnterQueue(T data)
        {
            // 访问临界资源
            _mutex.Lock();
            // 如果数据满了，那么等待消费者消费
            //伪唤醒
            while (IsFull())
            {
                p_wait_num++;
                p_cond.Wait(_mutex);
                //pthread_cond_wait(&p_cond, &_mutex);
                p_wait_num--;
            }
            _bq.push(data);
            //std::cout << "生产数据:" << data << std::endl;

            // 至少有数据被生产了，唤醒消费者
            if (c_wait_num)
            {
                //pthread_cond_signal(&c_cond);
                c_cond.Notify();
            }
            _mutex.Unlock();
        }
        void Pop(T *data)
        {
            // 访问临界资源
            _mutex.Lock();
            // 如果没有数据，那么消费者就等待
            //伪唤醒
            while (IsEmpty())
            {
                std::cout << "消费者等待" << std::endl;
                c_wait_num++;
                c_cond.Wait(_mutex);
                c_wait_num--;
                std::cout << "消费者被唤醒" << std::endl;
            }

            *data = _bq.front();
            _bq.pop();
            //std::cout << "获得数据:" << *data << std::endl;

            // 消费完了后，至少消费了个数据，队列有空位置
            // 唤醒，生产者
            if (p_wait_num)
            {
                //pthread_cond_signal(&p_cond);
                p_cond.Notify();
            }
            _mutex.Unlock();
        }

    private:
        std::queue<T> _bq;
        int _bq_num;
        int c_wait_num, p_wait_num;//有多少消费者，生产者等待
        Mutex _mutex; // 锁
        Cond c_cond;  // 消费者的条件变量
        Cond p_cond;  // 生产者的条件变量
    };
}
//version 1
// namespace BlockQueueModule
// {
//     // int gc_wait_num = 5,gp_wait_num = 5;
//     int gbq_num = 5;
//     template <class T>
//     class BlockQueue
//     {
//     private:
//         bool IsFull()
//         {
//             return _bq.size() == _bq_num;
//         }
//         bool IsEmpty()
//         {
//             return _bq.size() == 0;
//         }

//     public:
//         BlockQueue(int bq_num = gbq_num) : _bq_num(bq_num)
//         {
//             pthread_mutex_init(&_mutex, nullptr);
//             pthread_cond_init(&c_cond, nullptr);
//             pthread_cond_init(&p_cond, nullptr);
//         }
//         ~BlockQueue()
//         {
//             pthread_mutex_destroy(&_mutex);
//             pthread_cond_destroy(&c_cond);
//             pthread_cond_destroy(&p_cond);
//         }
//         void EnterQueue(T data)
//         {
//             // 访问临界资源
//             pthread_mutex_lock(&_mutex);
//             // 如果数据满了，那么等待消费者消费
//             //伪唤醒
//             while (IsFull())
//             {
//                 p_wait_num++;
//                 pthread_cond_wait(&p_cond, &_mutex);
//                 p_wait_num--;
//             }
//             _bq.push(data);
//             std::cout << "生产数据:" << data << std::endl;

//             // 至少有数据被生产了，唤醒消费者
//             if (c_wait_num)
//             {
//                 pthread_cond_signal(&c_cond);
//             }
//             pthread_mutex_unlock(&_mutex);
//         }
//         void Pop(T *data)
//         {
//             // 访问临界资源
//             pthread_mutex_lock(&_mutex);
//             // 如果没有数据，那么消费者就等待
//             //伪唤醒
//             while (IsEmpty())
//             {
//                 std::cout << "消费者等待" << std::endl;
//                 c_wait_num++;
//                 pthread_cond_wait(&c_cond, &_mutex);
//                 c_wait_num--;
//                 std::cout << "消费者被唤醒" << std::endl;
//             }

//             *data = _bq.front();
//             _bq.pop();
//             std::cout << "获得数据:" << *data << std::endl;

//             // 消费完了后，至少消费了个数据，队列有空位置
//             // 唤醒，生产者
//             if (p_wait_num)
//             {
//                 pthread_cond_signal(&p_cond);
//             }
//             pthread_mutex_unlock(&_mutex);
//         }

//     private:
//         std::queue<T> _bq;
//         int _bq_num;
//         int c_wait_num, p_wait_num;//有多少消费者，生产者等待
//         pthread_mutex_t _mutex; // 锁
//         pthread_cond_t c_cond;  // 消费者的条件变量
//         pthread_cond_t p_cond;  // 生产者的条件变量
//     };
// }